﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace KamLib
{
    using Converts;

    /// <summary>
    /// Вешается на свойства FormData
    /// </summary>
    public abstract class ConvertAttribute : Attribute
    {
        public string SourceField;

        /// <summary>
        /// Преобразует значение свойства FormData, которое передаётся в Entity
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual bool DataToEntity(object src, object dest, MemberInfo pdest, object value)
        {
            return false;
        }
        /// <summary>
        /// Возвращает Expression, который присваивается свойству FormData при select из таблицы
        /// </summary>
        /// <param name="p"></param>
        /// <param name="member"></param>
        /// <returns></returns>
        public virtual Expression InitBind(ParameterExpression p, MemberInfo member) { return null; }

        /// <summary>
        /// true - при формировании select expression создаётся вычисляемое поле
        /// </summary>
        /// <returns></returns>
        public virtual bool IsCalculate { get { return false; } }

        /// <summary>
        /// Копирует свойства из src в dest, с учётом атрибутов
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TDest"></typeparam>
        /// <param name="src"></param>
        /// <param name="dest"></param>
        /// <param name="canAssign">(SourceMember, DestMember)</param>
        public static void Copy<TSource, TDest>(TSource src, TDest dest,
            Func<MemberInfo, MemberInfo, bool> canAssign = null)
            where TDest : class
        {
            var t = dest.GetType();
            foreach (var psrc in src.GetType().GetPropertiesAndFields())
            {
                try
                {
                    var value = psrc.GetValue(src, null);

                    var pdest = t.GetProperty(psrc.Name);
                    if (pdest == null)
                    {
                        foreach (var convert in GetCustomAttributes(psrc, typeof(ConvertAttribute)).OfType<ConvertAttribute>())
                        {
                            convert.DataToEntity(src, dest, null, value);
                        }
                        continue;
                    }

                    if (!pdest.CanWrite) continue;

                    if (canAssign != null && !canAssign(psrc, pdest)) continue;

                    var converted = false;
                    foreach (var convert in GetCustomAttributes(psrc, typeof(ConvertAttribute)).OfType<ConvertAttribute>())
                    {
                        converted = convert.DataToEntity(src, dest, pdest, value);
                        if (converted) break;
                    }
                    if (!converted)
                        pdest.SetValue(dest, value, null);
                }
                catch (Exception ex)
                {
                    throw new Exception("Copy: property " + psrc.Name + ". " + ex.FullMessage());
                }
            }
        }

        public static void CopyFrom<TDest>(Dictionary<string, object> src, TDest dest,
            Func<KeyValuePair<string, object>, MemberInfo, bool> canAssign = null)
            where TDest : class
        {
            var t = dest.GetType();
            foreach (var psrc in src)
            {
                try
                {
                    var pdest = t.GetProperty(psrc.Key);
                    if (pdest == null || !pdest.CanWrite) continue;

                    if (canAssign != null && !canAssign(psrc, pdest)) continue;

                    pdest.SetValue(dest, psrc.Value.To(pdest.PropertyType), null);
                }
                catch (Exception ex)
                {
                    throw new Exception("Copy: property " + psrc.Key + ". " + ex.FullMessage());
                }
            }
        }

    }




    public class TrimAttribute : ConvertAttribute
    {
        public override bool DataToEntity(object src, object dest, MemberInfo pdest, object value)
        {
            pdest.SetValue(dest, value == null ? null : value.ToString().Trim(), null);
            return true;
        }
    }
    public class TrimEndAttribute : ConvertAttribute
    {
        public override bool DataToEntity(object src, object dest, MemberInfo pdest, object value)
        {
            pdest.SetValue(dest, value == null ? null : value.ToString().TrimEnd(), null);
            return true;
        }
    }
    public class TrimStartAttribute : ConvertAttribute
    {
        public override bool DataToEntity(object src, object dest, MemberInfo pdest, object value)
        {
            pdest.SetValue(dest, value == null ? null : value.ToString().TrimStart(), null);
            return true;
        }
    }
    public class PercentAttribute : ConvertAttribute
    {
        public override bool DataToEntity(object src, object dest, MemberInfo pdest, object value)
        {
            if (value is double?)
            {
                pdest.SetValue(dest, (double?)(((double?)value).Value / 100D), null);
                return true;
            }
            if (value is double)
            {
                pdest.SetValue(dest, ((double)value) / 100D, null);
                return true;
            }
            return false;
        }
        public override Expression InitBind(ParameterExpression p, MemberInfo member)
        {
            return Expression.Multiply(
                Expression.PropertyOrField(p, member.Name),
                Expression.Constant(100D, member.ResultType())
            );
        }
    }

    public class DateAttribute : ConvertAttribute
    {
        public DateAttribute() { }
        public DateAttribute(string sourceField)
        {
            SourceField = sourceField;
        }

        public override bool IsCalculate { get { return true; } }

        public override bool DataToEntity(object src, object dest, MemberInfo pdest, object value)
        {
            var v = value as string;
            var date = v == null ? null : (DateTime?)DateTime.Parse(v);

            if (SourceField != null)
            {
                pdest = dest.GetType().GetPropertyOrField(SourceField);
                if (pdest == null)
                    throw new Exception("Not found field/property '" + SourceField + "' in " + src.GetType().Name);
            }

            if (pdest == null) return false;

            var pdate = (DateTime?)pdest.GetValue(dest, null);

            if (pdate != null && date != null)
                date = date.Value.Date.Add(pdate.Value.TimeOfDay);
            var pdestType = pdest.ResultType();
            pdest.SetValue(dest, pdestType == typeof(DateTime)
                ? date != null ? (object)date.Value : DateTime.MinValue
                : date
                , null
            );
            return true;
        }
        public override Expression InitBind(ParameterExpression p, MemberInfo member)
        {
            return Expression.Call(mGetDate, Expression.PropertyOrField(p, member.Name));
        }

        private readonly static MethodInfo mGetDate = typeof(DateAttribute).GetMethod("GetDate", BindingFlags.Public | BindingFlags.Static);
        public static string GetDate(DateTime? value)
        {
            return value.HasValue ? value.Value.ToString(@"dd/MM/yyyy") : null;
        }
    }

    public class STimeAttribute : ConvertAttribute
    {
        public STimeAttribute() { }
        public STimeAttribute(string sourceField)
        {
            SourceField = sourceField;
        }

        public override bool DataToEntity(object src, object dest, MemberInfo pdest, object value)
        {
            var v = value as string;

            if (SourceField != null)
            {
                pdest = dest.GetType().GetPropertyOrField(SourceField);
                if (pdest == null)
                    throw new Exception("Not found field/property '" + SourceField + "' in " + src.GetType().Name);
            }
            if (pdest == null) return false;

            var pdestType = pdest.ResultType();
            if (pdestType != typeof(DateTime) || pdestType != typeof(DateTime?))
            {
                var pvalue = pdest.GetValue(dest, null);
                // ReSharper disable PossibleInvalidCastException
                var pdate = pvalue != null ? pvalue is DateTime ? (DateTime)pvalue : (DateTime?)pvalue : null;
                // ReSharper restore PossibleInvalidCastException
                pdate = pdate.SetTime(v);
                pdest.SetValue(dest, pdate, null);
                return true;
            }

            throw new Exception("The type of field/property '" + src.GetType().Name + "." + SourceField + "' is not supported.");
        }
        public override Expression InitBind(ParameterExpression p, MemberInfo member)
        {
            return Expression.Call(mGetTime, Expression.PropertyOrField(p, member.Name));
        }

        public override bool IsCalculate { get { return true; } }

        private readonly static MethodInfo mGetTime = typeof(STimeAttribute).GetMethod("GetTime", BindingFlags.Public | BindingFlags.Static);
        public static string GetTime(DateTime? value)
        {
            return value != null ? value.Value.ToString("HH\\:mm") : null;
        }
    }



    public static class ConvertHelper
    {
        [DebuggerStepThrough]
        public static T To<T>(this object value)
        {
            var t = typeof(T);
            return t == typeof(object) ? (T)value : (T)value.To(t);
        }
        [DebuggerStepThrough]
        public static object To(this object value, Type type)
        {

            if (value == null) return null;
            if (value.GetType() == type) return value;


            if (type == typeof(string))
                return value.ToString();

            if (type == typeof(int))
                return value.ToInt();
            if (type == typeof(int?))
                return value.ToIntn();

            if (type == typeof(decimal))
                return value.ToDecimal();
            if (type == typeof(decimal?))
                return value.ToDecimaln();

            if (type == typeof(double))
                return value.ToDouble();
            if (type == typeof(double?))
                return value.ToDoublen();

            if (type == typeof(DateTime))
                return value.ToDateTime();
            if (type == typeof(DateTime?))
                return value.ToDateTimen();
            if (type == typeof(bool))
                return value.ToBool();
            if (type == typeof(bool?))
                return value.ToBooln();

            if (type == typeof(float))
                return value.ToFloat();
            if (type == typeof(float?))
                return value.ToFloatn();

            if (type == typeof(long))
                return value.ToInt64();
            if (type == typeof(long?))
                return value.ToInt64n();

            return value;
        }

    }
}

namespace KamLib.Converts
{
    public static class ConvertHelper
    {

        #region ToBool

        [DebuggerStepThrough]
        public static bool ToBool(this object value, bool defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToBoolean(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static bool ToBool(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return false;
            return Convert.ToBoolean(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static bool? ToBooln(this object value, bool? defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToBoolean(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static bool? ToBooln(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return null;
            return Convert.ToBoolean(value);
        }


        [DebuggerStepThrough]
        public static bool ToBool(this string value, bool defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            bool res;
            return bool.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static bool ToBool(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return false;
            bool res;
            return bool.TryParse(value, out res) ? res : false;
        }

        [DebuggerStepThrough]
        public static bool? ToBooln(this string value, bool? defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            bool res;
            return bool.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static bool? ToBooln(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            bool res;
            return bool.TryParse(value, out res) ? (bool?)res : null;
        }

        [DebuggerStepThrough]
        public static string ToString(this bool? value)
        {
            return value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : null;
        }


        [DebuggerStepThrough]
        public static bool[] ToBool(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new bool[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToBool();
            return res;
        }
        [DebuggerStepThrough]
        public static bool?[] ToBooln(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new bool?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToBooln();
            return res;
        }

        [DebuggerStepThrough]
        public static bool[] ToBool(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new bool[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToBool();
            return res;
        }
        [DebuggerStepThrough]
        public static bool?[] ToBooln(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new bool?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToBooln();
            return res;
        }


        #endregion


        #region ToDateTime

        [DebuggerStepThrough]
        public static DateTime ToDateTime(this object value, DateTime defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToDateTime(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static DateTime ToDateTime(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return DateTime.MinValue;
            return Convert.ToDateTime(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static DateTime? ToDateTimen(this object value, DateTime? defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToDateTime(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static DateTime? ToDateTimen(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return null;
            return Convert.ToDateTime(value);
        }

        [DebuggerStepThrough]
        public static DateTime ToDateTime(this string value, DateTime defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            DateTime res;
            return DateTime.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static DateTime ToDateTime(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return DateTime.MinValue;
            DateTime res;
            return DateTime.TryParse(value, out res) ? res : DateTime.MinValue;
        }

        [DebuggerStepThrough]
        public static DateTime? ToDateTimen(this string value, DateTime? defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            DateTime res;
            return DateTime.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static DateTime? ToDateTimen(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            DateTime res;
            return DateTime.TryParse(value, out res) ? (DateTime?)res : null;
        }

        [DebuggerStepThrough]
        public static string ToString(this DateTime? value)
        {
            return value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this DateTime? value, string format)
        {
            return value.HasValue ? value.Value.ToString(format, CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this DateTime? value, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(provider) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this DateTime? value, string format, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(format, provider) : null;
        }


        [DebuggerStepThrough]
        public static DateTime[] ToDateTime(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new DateTime[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDateTime();
            return res;
        }
        [DebuggerStepThrough]
        public static DateTime?[] ToDateTimen(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new DateTime?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDateTimen();
            return res;
        }

        [DebuggerStepThrough]
        public static DateTime[] ToDateTime(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new DateTime[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDateTime();
            return res;
        }
        [DebuggerStepThrough]
        public static DateTime?[] ToDateTimen(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new DateTime?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDateTimen();
            return res;
        }

        #endregion


        #region ToDouble

        [DebuggerStepThrough]
        public static double ToDouble(this object value, double defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToDouble(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static double ToDouble(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return 0;
            return Convert.ToDouble(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static double? ToDoublen(this object value, double? defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToDouble(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static double? ToDoublen(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return null;
            return Convert.ToDouble(value);
        }


        [DebuggerStepThrough]
        public static double ToDouble(this string value, double defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            double res;
            return double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static double ToDouble(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return 0;
            double res;
            return double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : 0;
        }

        [DebuggerStepThrough]
        public static double? ToDoublen(this string value, double? defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            double res;
            return double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static double? ToDoublen(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            double res;
            return double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? (double?)res : null;
        }

        [DebuggerStepThrough]
        public static string ToString(this double? value)
        {
            return value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this double? value, string format)
        {
            return value.HasValue ? value.Value.ToString(format, CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this double? value, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(provider) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this double? value, string format, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(format, provider) : null;
        }


        [DebuggerStepThrough]
        public static double[] ToDouble(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new double[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDouble();
            return res;
        }
        [DebuggerStepThrough]
        public static double?[] ToDoublen(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new double?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDoublen();
            return res;
        }

        [DebuggerStepThrough]
        public static double[] ToDouble(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new double[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDouble();
            return res;
        }
        [DebuggerStepThrough]
        public static double?[] ToDoublen(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new double?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDoublen();
            return res;
        }


        #endregion


        #region ToDecimal

        [DebuggerStepThrough]
        public static decimal ToDecimal(this object value, decimal defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToDecimal(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static decimal ToDecimal(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return 0;
            return Convert.ToDecimal(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static decimal? ToDecimaln(this object value, decimal? defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToDecimal(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static decimal? ToDecimaln(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return null;
            return Convert.ToDecimal(value);
        }


        [DebuggerStepThrough]
        public static decimal ToDecimal(this string value, decimal defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            decimal res;
            return decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static decimal ToDecimal(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return 0;
            decimal res;
            return decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : 0;
        }

        [DebuggerStepThrough]
        public static decimal? ToDecimaln(this string value, decimal? defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            decimal res;
            return decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static decimal? ToDecimaln(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            decimal res;
            return decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? (decimal?)res : null;
        }

        [DebuggerStepThrough]
        public static string ToString(this decimal? value)
        {
            return value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this decimal? value, string format)
        {
            return value.HasValue ? value.Value.ToString(format, CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this decimal? value, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(provider) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this decimal? value, string format, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(format, provider) : null;
        }


        [DebuggerStepThrough]
        public static decimal[] ToDecimal(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new decimal[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDecimal();
            return res;
        }
        [DebuggerStepThrough]
        public static decimal?[] ToDecimaln(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new decimal?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDecimaln();
            return res;
        }

        [DebuggerStepThrough]
        public static decimal[] ToDecimal(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new decimal[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDecimal();
            return res;
        }
        [DebuggerStepThrough]
        public static decimal?[] ToDecimaln(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new decimal?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToDecimaln();
            return res;
        }

        #endregion


        #region ToFloat

        [DebuggerStepThrough]
        public static float ToFloat(this object value, float defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return (float)Convert.ToDouble(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static float ToFloat(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return 0;
            return (float)Convert.ToDouble(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static float? ToFloatn(this object value, float? defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return (float)Convert.ToDouble(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static float? ToFloatn(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return null;
            return (float)Convert.ToDouble(value);
        }


        [DebuggerStepThrough]
        public static float ToFloat(this string value, float defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            float res;
            return float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static float ToFloat(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return 0;
            float res;
            return float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : 0;
        }

        [DebuggerStepThrough]
        public static float? ToFloatn(this string value, float? defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            float res;
            return float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static float? ToFloatn(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            float res;
            return float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out res) ? (float?)res : null;
        }

        [DebuggerStepThrough]
        public static string ToString(this float? value)
        {
            return value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this float? value, string format)
        {
            return value.HasValue ? value.Value.ToString(format, CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this float? value, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(provider) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this float? value, string format, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(format, provider) : null;
        }


        [DebuggerStepThrough]
        public static float[] ToFloat(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new float[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToFloat();
            return res;
        }
        [DebuggerStepThrough]
        public static float?[] ToFloatn(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new float?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToFloatn();
            return res;
        }

        [DebuggerStepThrough]
        public static float[] ToFloat(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new float[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToFloat();
            return res;
        }
        [DebuggerStepThrough]
        public static float?[] ToFloatn(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new float?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToFloatn();
            return res;
        }


        #endregion


        #region ToInt

        [DebuggerStepThrough]
        public static int ToInt(this object value, int defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToInt32(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static int ToInt(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return 0;
            return Convert.ToInt32(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static int? ToIntn(this object value, int? defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToInt32(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static int? ToIntn(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return null;
            return Convert.ToInt32(value);
        }


        [DebuggerStepThrough]
        public static int ToInt(this string value, int defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            int res;
            return int.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static int ToInt(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return 0;
            int res;
            return int.TryParse(value, out res) ? res : 0;
        }

        [DebuggerStepThrough]
        public static int? ToIntn(this string value, int? defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            int res;
            return int.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static int? ToIntn(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            int res;
            return int.TryParse(value, out res) ? (int?)res : null;
        }

        [DebuggerStepThrough]
        public static string ToString(this int? value)
        {
            return value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this int? value, string format)
        {
            return value.HasValue ? value.Value.ToString(format, CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this int? value, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(provider) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this int? value, string format, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(format, provider) : null;
        }

        [DebuggerStepThrough]
        public static int[] ToInt(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new int[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToInt();
            return res;
        }
        [DebuggerStepThrough]
        public static int?[] ToIntn(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new int?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToIntn();
            return res;
        }

        [DebuggerStepThrough]
        public static int[] ToInt(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new int[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToInt();
            return res;
        }
        [DebuggerStepThrough]
        public static int?[] ToIntn(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new int?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToIntn();
            return res;
        }


        #endregion


        #region ToInt64

        [DebuggerStepThrough]
        public static Int64 ToInt64(this object value, Int64 defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToInt64(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static Int64 ToInt64(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return 0;
            return Convert.ToInt64(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static Int64? ToInt64n(this object value, Int64? defValue)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return defValue;
            return Convert.ToInt64(value, CultureInfo.InvariantCulture);
        }

        [DebuggerStepThrough]
        public static Int64? ToInt64n(this object value)
        {
            string s;
            if (value == null || Convert.IsDBNull(value) || ((s = value as string) != null && String.IsNullOrEmpty(s)))
                return null;
            return Convert.ToInt64(value);
        }


        [DebuggerStepThrough]
        public static Int64 ToInt64(this string value, Int64 defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            Int64 res;
            return Int64.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static Int64 ToInt64(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return 0;
            Int64 res;
            return Int64.TryParse(value, out res) ? res : 0;
        }

        [DebuggerStepThrough]
        public static Int64? ToInt64n(this string value, Int64? defValue)
        {
            if (String.IsNullOrEmpty(value))
                return defValue;
            Int64 res;
            return Int64.TryParse(value, out res) ? res : defValue;
        }

        [DebuggerStepThrough]
        public static Int64? ToInt64n(this string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            Int64 res;
            return Int64.TryParse(value, out res) ? (Int64?)res : null;
        }

        [DebuggerStepThrough]
        public static string ToString(this Int64? value)
        {
            return value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this Int64? value, string format)
        {
            return value.HasValue ? value.Value.ToString(format, CultureInfo.InvariantCulture) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this Int64? value, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(provider) : null;
        }
        [DebuggerStepThrough]
        public static string ToString(this Int64? value, string format, IFormatProvider provider)
        {
            return value.HasValue ? value.Value.ToString(format, provider) : null;
        }

        [DebuggerStepThrough]
        public static Int64[] ToInt64(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new Int64[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToInt64();
            return res;
        }
        [DebuggerStepThrough]
        public static Int64?[] ToInt64n(this object[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new Int64?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToInt64n();
            return res;
        }

        [DebuggerStepThrough]
        public static Int64[] ToInt64(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new Int64[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToInt64();
            return res;
        }
        [DebuggerStepThrough]
        public static Int64?[] ToInt64n(this string[] values)
        {
            if (values == null) return null;
            var len = values.Length;
            var res = new Int64?[len];
            for (var i = 0; i < len; ++i)
                res[i] = values[i].ToInt64n();
            return res;
        }


        #endregion



        /// <summary>
        /// Возвращает Dictionary со списком свойств объекта.
        /// </summary>
        [DebuggerStepThrough]
        public static Dictionary<string, object> ToPropDictionary(this object values)
        {
            if (values == null) return null;
            var props = TypeDescriptor.GetProperties(values);

            var dic = new Dictionary<string, object>(props.Count);
            foreach (PropertyDescriptor prop in props)
            {
                var value = prop.GetValue(values);
                if (value != null)
                    dic.Add(prop.Name, value);
            }
            return dic;
        }

        /// <summary>
        /// Возвращает Dictionary со списком свойств объекта заданного типа.
        /// </summary>
        [DebuggerStepThrough]
        public static Dictionary<string, T> ToPropDictionary<T>(this object values)
        {
            if (values == null) return new Dictionary<string, T>();
            var props = values.GetType().GetProperties();

            var dic = new Dictionary<string, T>(props.Length);

            foreach (var prop in props)
            {
                var value = prop.GetValue(values, null);
                if (value is T)
                    dic.Add(prop.Name, (T)value);
            }
            return dic;
        }

        /// <summary>
        /// Возвращает Dictionary со списком свойств объекта заданного типа.
        /// Предварительно преобразует с помощью convert
        /// </summary>
        //[DebuggerStepThrough]
        public static Dictionary<string, T> ToPropDictionary<T>(this object values, Func<PropertyInfo, object, T> convert)
            where T : class
        {
            if (values == null) return new Dictionary<string, T>();
            var props = values.GetType().GetProperties();

            var dic = new Dictionary<string, T>(props.Length);

            if (convert != null)
                foreach (var prop in props)
                {
                    T value = convert(prop, prop.GetValue(values, null));
                    if (value != null)
                        dic.Add(prop.Name, value);
                }
            else
                foreach (var prop in props)
                {
                    var value = prop.GetValue(values, null) as T;
                    if (value != null)
                        dic.Add(prop.Name, value);
                }

            return dic;
        }

    }
}